#pragma once

#include <algorithm>
#include "vtkActorCollection.h"
#include <BRep_Tool.hxx>
#include <Standard_Handle.hxx>
#include "Render/QIVtkSelectionPipeline.h"

enum class BooleanOP : uint8_t
{
	Union = 0,
	Intersect,
	Subtract
};

namespace Colors
{
	// 背景颜色
	static double Background[3] = { 0.75,0.75,0.75 };
	// Actor确认创建
	static double ActorCreated[3] = { 1,0.64453125,0 };
	static double ActorSelected[3] = { 0.0,1.0,0.0 };
	static double ActorHover[3] = { 1,0,0 };
}

// 比较两个同类型值是否近似相等，允许自定义相对误差epsilon
template <typename T>
bool IsNearlyEqual(T a, T b, T epsilon = std::numeric_limits<T>::epsilon())
{
	if (a == b)
	{
		return true;
	}
	T absA = std::abs(a);
	T absB = std::abs(b);
	T diff = std::abs(a - b);
	T relativeError = std::max(absA, absB) * epsilon;
	return diff <= relativeError;
}

// 处理不同类型的比较，epsilon类型为两者的共同类型
template <typename T, typename U>
bool IsNearlyEqual(T a, U b, std::common_type_t<T, U> epsilon = std::numeric_limits<std::common_type_t<T, U>>::epsilon())
{
	using CommonType = std::common_type_t<T, U>;
	return IsNearlyEqual(static_cast<CommonType>(a), static_cast<CommonType>(b), epsilon);
}

// 判断值是否接近零，使用绝对误差，epsilon为绝对阈值
template <typename T>
bool IsNearlyZero(T a, T epsilon = std::numeric_limits<T>::epsilon())
{
	return std::abs(a) <= epsilon;
}

extern bool ContainsActor(const std::vector<Handle(QIVtkSelectionPipeline)>& actorCollection, const Handle(QIVtkSelectionPipeline)& actorToFind);

extern void RemoveActor(std::vector<Handle(QIVtkSelectionPipeline)>& actorCollection, const Handle(QIVtkSelectionPipeline)& actorToRemove);

extern int GetIndexFromActor(const std::vector<Handle(QIVtkSelectionPipeline)>& actorCollection, const Handle(QIVtkSelectionPipeline)& actorToFind);

extern Handle(QIVtkSelectionPipeline) GetActorFromIndex(const std::vector<Handle(QIVtkSelectionPipeline)>& actorCollection, int index);

extern bool ContainsVertex(const std::vector<gp_Pnt>& points, const gp_Pnt& point, const Standard_Real theLinearTolerance = Precision::Confusion());

extern bool ContainsVertex(gp_Pnt& findPoint, const std::vector<gp_Pnt>& points, const gp_Pnt& point, const Standard_Real theLinearTolerance = Precision::Confusion());

// 获得边上等分点
extern std::vector<gp_Pnt> getDividedPointsOnEdge(const TopoDS_Edge& edge, int divisions);

// 获得圆心点
extern bool GetArcCenter(const TopoDS_Edge& edge, gp_Pnt& center);

// 获得椭圆心点
extern bool GetEllipseCenter(const TopoDS_Edge& edge, gp_Pnt& center);

// 获得面中心点
extern bool GetFaceParametricCenter(const TopoDS_Face& face, gp_Pnt& center);

// 获得两条线段的交点
extern std::vector<gp_Pnt> GetEdgeIntersections(const TopoDS_Edge& edge1, const TopoDS_Edge& edge2, double tolerance = Precision::Confusion());

// 判断拓扑形状的包围盒是否相交
extern bool IsBoundingBoxesIntersect(const TopoDS_Shape& shape1, const TopoDS_Shape& shape2);

// 判断点是否在曲线上
extern bool IsPointOnEdge(const gp_Pnt& thePoint, const TopoDS_Edge& theEdge, const double tolerance = Precision::Confusion());

// 获取一条曲线的端点
extern bool GetEdgeEndPoints(const TopoDS_Edge& theEdge, gp_Pnt& p1, gp_Pnt& p2, const double tolerance = Precision::Confusion());

// 获得点到曲线的距离
extern double DistancePointToEdgeGeometric(const gp_Pnt& point, const TopoDS_Edge& edge);

extern gp_Vec GetEdgeDirection(const TopoDS_Edge& edge);

extern bool operator== (const gp_XYZ& lhs, const gp_XYZ& rhs);
extern bool operator!= (const gp_XYZ& lhs, const gp_XYZ& rhs);
extern bool operator== (const gp_Pnt& lhs, const gp_Pnt& rhs);
extern bool operator!= (const gp_Pnt& lhs, const gp_Pnt& rhs);
extern bool operator== (const gp_Dir& lhs, const gp_Dir& rhs);
extern bool operator!= (const gp_Dir& lhs, const gp_Dir& rhs);
extern bool operator== (const gp_Ax1& lhs, const gp_Ax1& rhs);
extern bool operator!= (const gp_Ax1& lhs, const gp_Ax1& rhs);
extern bool operator== (const gp_Ax2& lhs, const gp_Ax2& rhs);
extern bool operator!= (const gp_Ax2& lhs, const gp_Ax2& rhs);

extern gp_Pnt operator+(const gp_Pnt& p1, const gp_Pnt& p2);
extern gp_Pnt operator-(const gp_Pnt& p1, const gp_Pnt& p2);
extern gp_Pnt operator*(const gp_Pnt& p, float n);
